/**
 * 去重服务
 * 检测和识别重复的交易记录
 */

class DeduplicationService {
  /**
   * 检测重复交易
   * 基于：时间窗口(±5分钟) + 金额(±0.01) + 商户相似度
   * @param {Object} newTransaction - 新交易记录
   * @param {Array} existingTransactions - 现有交易记录
   * @param {Object} rules - 去重规则
   * @returns {Array} 重复记录数组
   */
  static async findDuplicates(newTransaction, existingTransactions, rules = {}) {
    const timeWindow = rules.time_window || 300; // 默认5分钟 (300秒)
    const amountTolerance = rules.amount_tolerance || 0.01; // 默认金额容差0.01元
    const similarityThreshold = rules.merchant_similarity || 80; // 默认相似度阈值80%

    const duplicates = [];

    for (const existing of existingTransactions) {
      try {
        // 1. 时间窗口检查
        const newTime = new Date(newTransaction.transaction_time);
        const existingTime = new Date(existing.date);
        const timeDiff = Math.abs(newTime - existingTime) / 1000; // 秒
        
        if (timeDiff > timeWindow) continue;

        // 2. 金额检查
        const amountDiff = Math.abs(newTransaction.amount - existing.amount);
        if (amountDiff > amountTolerance) continue;

        // 3. 收支类型必须一致
        if (newTransaction.type !== existing.type) continue;

        // 4. 商户相似度检查
        const newMerchant = newTransaction.merchant || newTransaction.description || '';
        const existingMerchant = existing.remark || '';
        
        const similarity = this.calculateSimilarity(
          newMerchant.toLowerCase(),
          existingMerchant.toLowerCase()
        );

        if (similarity >= similarityThreshold) {
          duplicates.push({
            existing_id: existing.record_id,
            existing_data: existing,
            similarity: similarity.toFixed(2),
            time_diff: timeDiff.toFixed(2),
            amount_diff: amountDiff.toFixed(2),
            match_score: this.calculateMatchScore(similarity, timeDiff, amountDiff)
          });
        }
      } catch (error) {
        console.error('去重检查出错:', error.message);
      }
    }

    // 按匹配分数排序，返回最相似的
    duplicates.sort((a, b) => b.match_score - a.match_score);

    return duplicates;
  }

  /**
   * 计算匹配分数（综合考虑相似度、时间差、金额差）
   * @param {number} similarity - 相似度
   * @param {number} timeDiff - 时间差（秒）
   * @param {number} amountDiff - 金额差
   * @returns {number} 匹配分数
   */
  static calculateMatchScore(similarity, timeDiff, amountDiff) {
    // 相似度权重60%，时间权重30%，金额权重10%
    const similarityScore = similarity;
    const timeScore = Math.max(0, 100 - (timeDiff / 3)); // 时间越近分数越高
    const amountScore = amountDiff === 0 ? 100 : Math.max(0, 100 - (amountDiff * 100));
    
    return (similarityScore * 0.6) + (timeScore * 0.3) + (amountScore * 0.1);
  }

  /**
   * 计算字符串相似度（Levenshtein距离算法）
   * @param {string} str1 - 字符串1
   * @param {string} str2 - 字符串2
   * @returns {number} 相似度百分比 (0-100)
   */
  static calculateSimilarity(str1, str2) {
    if (!str1 || !str2) return 0;
    if (str1 === str2) return 100;

    const len1 = str1.length;
    const len2 = str2.length;

    // 如果长度差异过大，直接返回较低相似度
    if (Math.abs(len1 - len2) > Math.max(len1, len2) * 0.5) {
      return 0;
    }

    // 创建编辑距离矩阵
    const matrix = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(0));

    // 初始化第一行和第一列
    for (let i = 0; i <= len1; i++) matrix[i][0] = i;
    for (let j = 0; j <= len2; j++) matrix[0][j] = j;

    // 计算编辑距离
    for (let i = 1; i <= len1; i++) {
      for (let j = 1; j <= len2; j++) {
        const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
        matrix[i][j] = Math.min(
          matrix[i - 1][j] + 1,      // 删除
          matrix[i][j - 1] + 1,      // 插入
          matrix[i - 1][j - 1] + cost // 替换
        );
      }
    }

    const distance = matrix[len1][len2];
    const maxLen = Math.max(len1, len2);
    
    // 转换为相似度百分比
    return ((maxLen - distance) / maxLen) * 100;
  }

  /**
   * 批量去重检查
   * @param {Array} newTransactions - 新交易记录数组
   * @param {Array} existingTransactions - 现有交易记录
   * @param {Object} rules - 去重规则
   * @returns {Array} 去重结果
   */
  static async batchFindDuplicates(newTransactions, existingTransactions, rules) {
    const results = [];

    for (const newTx of newTransactions) {
      const duplicates = await this.findDuplicates(newTx, existingTransactions, rules);
      results.push({
        transaction: newTx,
        is_duplicate: duplicates.length > 0,
        duplicates: duplicates,
        best_match: duplicates[0] || null
      });
    }

    return results;
  }

  /**
   * 检查平台交易ID是否已存在
   * @param {string} platformTransactionId - 平台交易ID
   * @param {Array} existingTransactions - 现有交易记录
   * @returns {boolean} 是否存在
   */
  static checkPlatformTransactionId(platformTransactionId, existingTransactions) {
    if (!platformTransactionId) return false;
    
    return existingTransactions.some(tx => {
      try {
        const rawData = typeof tx.raw_data === 'string' 
          ? JSON.parse(tx.raw_data) 
          : tx.raw_data;
        return rawData?.transactionId === platformTransactionId;
      } catch (e) {
        return false;
      }
    });
  }
}

module.exports = DeduplicationService;

